/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.stuffrepos.bricknetcenter.util.gui.inputtable;

import java.awt.Color;
import java.text.ParseException;
import java.util.Date;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import net.stuffrepos.bricknetcenter.util.BuilderFactory;
import net.stuffrepos.bricknetcenter.util.LocaleHelper;
import net.stuffrepos.bricknetcenter.util.validation.Property;

/**
 *
 * @author Eduardo H. Bogoni <eduardobogoni@gmail.com>
 */
public class InputCellFactory {

    private static BuilderFactory.ClassKeyed<Property, InputCell> inputBuilder = new BuilderFactory.ClassKeyed<Property, InputCell>(false) {

        @Override
        protected Class getSourceKey(Property source) {
            return source.getPropertyType();
        }
    };

    static {
        inputBuilder.addBuilder(Integer.class, new BuilderFactory.Builder<Property, InputCell>() {

            @Override
            public InputCell build(Property source) {
                return new DefaultCellInput<Integer>() {

                    @Override
                    public Integer parseValue(Object obj) {
                        if (obj == null) {
                            return null;
                        } else {
                            return Integer.parseInt(obj.toString());
                        }
                    }

                    @Override
                    public boolean isValidValue(Object obj) {
                        try {
                            parseValue(obj);
                            return true;
                        } catch (NumberFormatException exception) {
                            return false;
                        }
                    }
                };
            }
        });

        inputBuilder.addBuilder(String.class, new BuilderFactory.Builder<Property, InputCell>() {

            @Override
            public InputCell build(Property source) {
                return new DefaultCellInput<String>() {

                    @Override
                    public Object parseValue(Object obj) {
                        return (obj == null ? null : obj.toString());
                    }

                    @Override
                    public boolean isValidValue(Object obj) {
                        return true;
                    }
                };
            }
        });

        inputBuilder.addBuilder(Date.class, new BuilderFactory.Builder<Property, InputCell>() {

            @Override
            public InputCell build(Property source) {
                return new DefaultCellInput<Date>() {

                    @Override
                    public Object parseValue(Object obj) {
                        try {
                            return obj == null ? null : LocaleHelper.getDateOnlyInputFormat().parse(obj.toString());
                        } catch (ParseException ex) {
                            throw new RuntimeException(ex);
                        }
                    }

                    @Override
                    public boolean isValidValue(Object obj) {
                        try {
                            if (obj == null) {
                                return true;
                            } else {
                                LocaleHelper.getDateOnlyInputFormat().parse(obj.toString());
                                return true;
                            }
                        } catch (ParseException ex) {
                            return false;
                        }

                    }
                };
            }
        });

        inputBuilder.addBuilder(Enum.class, new BuilderFactory.Builder<Property, InputCell>() {

            @Override
            public InputCell build(Property source) {
                JComboBox comboBox = new JComboBox(source.getPropertyType().getEnumConstants());
                return new DefaultCellInput<Enum>(new DefaultCellEditor(comboBox)) {

                    @Override
                    public Enum parseValue(Object obj) {
                        if (obj == null) {
                            return null;
                        } else {
                            return (Enum) obj;
                        }
                    }

                    @Override
                    public boolean isValidValue(Object obj) {
                        try {
                            if (obj == null) {
                                return true;
                            } else {
                                Enum e = (Enum) obj;
                                return true;
                            }

                        } catch (ClassCastException ex) {
                            return false;
                        }
                    }
                };
            }
        });
    }

    public static InputCell newInput(Property property) {
        return inputBuilder.getResult(property);
    }

    private static abstract class DefaultCellInput<ValueType> implements InputCell {

        private TableCellEditor editor;
        private TableCellRenderer validRenderer;
        private final TableCellRenderer invalidRenderer;

        public DefaultCellInput(TableCellEditor editor, TableCellRenderer validRenderer, TableCellRenderer invalidRenderer) {
            this.editor = editor;
            this.validRenderer = validRenderer;
            this.invalidRenderer = invalidRenderer;
        }

        public DefaultCellInput(TableCellEditor editor, TableCellRenderer renderer) {
            this(editor, renderer, null);
        }

        public DefaultCellInput(TableCellEditor editor) {
            this(editor, new DefaultValidValueRenderer(), new DefaultInvalidValueRenderer());
        }

        public DefaultCellInput() {
            this(new DefaultCellEditor(new JTextField()));
        }

        @Override
        public TableCellEditor getEditor() {
            return editor;
        }

        @Override
        public TableCellRenderer getValidValueRenderer() {
            return validRenderer;
        }

        @Override
        public TableCellRenderer getInvalidValueRenderer() {
            return (invalidRenderer == null ? validRenderer : invalidRenderer);
        }

        private static class DefaultValidValueRenderer extends DefaultTableCellRenderer {
        }

        private static class DefaultInvalidValueRenderer extends DefaultTableCellRenderer {

            public DefaultInvalidValueRenderer() {
                this.setOpaque(true);
                this.setBackground(Color.red);
                this.setForeground(Color.white);
            }
        }
    }
}
